package main

import (
	"errors"
	"fmt"
	pb "ihos/ihos"
	"log"
	"time"

	tm "github.com/golang/protobuf/ptypes/timestamp"
)

type shipin_request struct {
	id        int32 //PK
	from_yhid int32 //发起人用户ID shipin_yonghu PK
	to_yhid   int32 //接收人用户ID shipin_yonghu PK
	jlsj      int64 //建立时间
	sxsj      int64 //失效时间
	zl        int32 //指令
	flag      int32 //1-removed
}

// id: PK of record to be read
func (w *shipin_request) GetFromDB(id int32) error {
	sql := "SELECT id,from_yhid,to_yhid,jlsj,sxsj,zl,flag FROM shipin_request WHERE id=$1"
	return DBConn.db.QueryRow(sql, id).Scan(&w.id, &w.from_yhid, &w.to_yhid, &w.jlsj, &w.sxsj, &w.zl, &w.flag)
}

// from_yhid
func (w *shipin_request) GetByFrom(from_yhid int32) error {
	fmt.Println("getbyfrom:", from_yhid)
	sql := "SELECT id,from_yhid,to_yhid,jlsj,sxsj,zl,flag FROM shipin_request WHERE from_yhid=$1 order by id desc limit 1"
	return DBConn.db.QueryRow(sql, from_yhid).Scan(&w.id, &w.from_yhid, &w.to_yhid, &w.jlsj, &w.sxsj, &w.zl, &w.flag)
}

//id: PK of record to be save
//    0  - insert
//    >0 - update
func (w *shipin_request) SaveToDB(id int32) error {
	sql := ""
	var err error
	if id > 0 { //update
		sql = "UPDATE shipin_request set from_yhid=$1,to_yhid=$2,jlsj=$3,sxsj=$4,zl=$5,flag=$6 where id=$7 RETURNING id"
		err = DBConn.db.QueryRow(sql, w.from_yhid, w.to_yhid, w.jlsj, w.sxsj, w.zl, w.flag, w.id).Scan(&w.id)
	} else { //insert
		sql = "INSERT INTO shipin_request(from_yhid,to_yhid,jlsj,sxsj,zl,flag) VALUES($1,$2,$3,$4,$5,$6) RETURNING id"
		err = DBConn.db.QueryRow(sql, w.from_yhid, w.to_yhid, w.jlsj, w.sxsj, w.zl, w.flag).Scan(&w.id)
	}
	return err
}

func (w *shipin_request) SavePbShiPinRequest(in *pb.ShiPinRequestL6) error {
	log.Println("SavePbShiPinRequest", in)
	s := &shipin{}
	if err := s.GetFromDB(in.GetTO().GetSPXX().GetID()); err != nil {
		return errors.New("CANNOT FOUND SHIPIN")
	}
	// log.Println("SHIPIN:", s)
	if in.GetJLSJ() == nil || in.GetJLSJ().GetSeconds() == 0 {
		in.JLSJ = &tm.Timestamp{Seconds: time.Now().Unix()}
	}
	if in.GetSXSJ() == nil || in.GetSXSJ().GetSeconds() == 0 {
		in.SXSJ = &tm.Timestamp{Seconds: in.GetJLSJ().GetSeconds() + VIDEO_REQUEST_TIMEOUT}
	}
	yh := new(shipin_yonghu).fromPB(in.GetFROM())
	if yh.id == 0 {
		yh.SaveToDB(0)
	}
	in.FROM = yh.toPB()
	w.from_yhid = in.GetFROM().GetID()
	yh.fromPB(in.GetTO())
	if yh.id == 0 {
		yh.SaveToDB(0)
	}
	in.TO = yh.toPB()
	w.to_yhid = in.GetTO().GetID()
	w.jlsj = in.GetJLSJ().GetSeconds()
	w.sxsj = in.GetSXSJ().GetSeconds()
	w.zl = int32(in.GetZL())
	// w.flag = 0
	return w.SaveToDB(w.id)
}

// 客服，患者都可以设置所属医院，如果客服设置了所属医院，则只能抓取该医院所属的患者请求；
// 如果患者有所属医院，其请求会优先被该医院客服抓取，超时后才会被公司客服抓取，公司客服指没有设置所属医院的客服
// 如果患者没有所属医院，则请求会立刻被公司客服抓取
func (w *shipin_request) SelectByPbShiPinYongHu(in *pb.ShiPinYongHuL5) (*pb.ShiPinRequestListL7, error) {
	// log.Println("SelectByPbShiPinYongHu:", in)
	out := new(pb.ShiPinRequestListL7)
	t := time.Now().Unix()
	//sql := "SELECT sr.id,sr.from_yhid,sr.to_yhid,sr.jlsj,sr.sxsj,sr.zl,sr.flag FROM shipin_request as sr, shipin_yonghu as yh WHERE sr.to_yhid=yh.id AND sr.flag=0 AND yh.yhlx=" + fmt.Sprint(int32(in.GetLX())) + " AND sxsj>" + fmt.Sprint(t)
	//读取当前未超时的指令数据，以及指令携带的from和to的视频用户数据，to用户类型和请求获取指令的用户类型需匹配
	sql := "SELECT sr.id,sr.from_yhid,sr.to_yhid,sr.jlsj,sr.sxsj,sr.zl,sr.flag,fyh.id,fyh.yhid,fyh.yhlx,tyh.id,tyh.yhid,tyh.yhlx FROM shipin_request as sr, shipin_yonghu as fyh,shipin_yonghu as tyh WHERE sr.from_yhid=fyh.id AND sr.to_yhid=tyh.id AND sr.flag=0 AND tyh.yhlx=" + fmt.Sprint(int32(in.GetLX())) + " AND sxsj>" + fmt.Sprint(t)
	if in.GetLX() != pb.YHLX_KEFU && in.GetYHID() > 0 {
		sql += " AND tyh.yhid=" + fmt.Sprint(in.GetYHID())
	}
	sql += " ORDER BY sr.id DESC LIMIT 5"
	// log.Println(sql)
	rows, err := DBConn.db.Query(sql)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	defer rows.Close()
	for rows.Next() {
		sr := &shipin_request{}
		fyh := &shipin_yonghu{}
		tyh := &shipin_yonghu{}
		if err = rows.Scan(&sr.id, &sr.from_yhid, &sr.to_yhid, &sr.jlsj, &sr.sxsj, &sr.zl, &sr.flag, &fyh.id, &fyh.yhid, &fyh.yhlx, &tyh.id, &tyh.yhid, &tyh.yhlx); err != nil {
			log.Println(err)
			return nil, err
			// break
		}
		// log.Println("ROW:", *sr, *fyh, *tyh)
		if fyh.toPB().GetLX() == pb.YHLX_HUANZHE && tyh.toPB().GetLX() == pb.YHLX_KEFU {
			// 医院延迟时间是否到达，医院客服优先获取指令，超时后由后台公司客服处理
			// 患者所属医院，客服所属医院，医院服务超时
			h := new(huanzhe)
			if fyh.yhid > 0 {
				if err = h.GetFromDB(fyh.yhid); err != nil {
					log.Println(err)
					continue
				}
			}
			k := new(kefu)
			if in.GetYHID() > 0 {
				if err = k.GetFromDB(in.GetYHID()); err != nil {
					log.Println(err)
					continue
				}
			}
			y := new(yiyuan)
			if h.yiyuan_id > 0 {
				if err = y.GetFromDB(h.yiyuan_id); err != nil {
					log.Println(err)
					continue
				}
			}
			// log.Println("huanzhe:", h)
			// log.Println("kefu:", k)
			// log.Println("yiyuan:", y)
			//属于特定医院的客服只能处理该医院的患者
			if k.yy_id > 0 && k.yy_id != h.yiyuan_id {
				continue
			}
			//属于特定医院的患者超时后由后台公司客服处理
			if h.yiyuan_id > 0 && k.yy_id == 0 {
				// log.Println("jlsj:", sr.jlsj, y.delay, t)
				if sr.jlsj+int64(y.delay) > t {
					continue
				}
				log.Println("backup kefu takes hospital huanzhe request")
			}

			if k.yy_id > 0 && k.yy_id == h.yiyuan_id {
				log.Println("hospital kefu takes hospital request")
			}

			if k.yy_id == 0 && h.yiyuan_id == 0 {
				log.Println("backup kefu takes common request")
			}
		}
		pr := sr.toPB()
		// log.Println("PR:", pr)
		out.SPRS = append(out.SPRS, pr)
	}
	// log.Println("OUT:", out)
	return out, nil
}

func (w *shipin_request) Remove(id int32) error {
	sql := "UPDATE shipin_request set flag=1 WHERE id=$1 RETURNING id"
	return DBConn.db.QueryRow(sql, id).Scan(&w.id)
}

func (w *shipin_request) toPB() *pb.ShiPinRequestL6 {
	p := &pb.ShiPinRequestL6{
		ID:   w.id,
		JLSJ: &tm.Timestamp{Seconds: w.jlsj},
		SXSJ: &tm.Timestamp{Seconds: w.sxsj},
		ZL:   pb.ShiPinRequestL6_SPZL(w.zl),
	}
	from := &shipin_yonghu{id: w.from_yhid}
	from.GetFromDB(from.id)
	// log.Println("FROM:", from)
	p.FROM = from.toPB()
	to := &shipin_yonghu{id: w.to_yhid}
	to.GetFromDB(to.id)
	// log.Println("TO:", to)
	p.TO = to.toPB()
	return p
}

func (w *shipin_request) fromPB(p *pb.ShiPinRequestL6) *shipin_request {
	w.id = p.GetID()
	w.from_yhid = p.GetFROM().GetID()
	w.to_yhid = p.GetTO().GetID()
	w.jlsj = p.GetJLSJ().GetSeconds()
	w.sxsj = p.GetSXSJ().GetSeconds()
	w.zl = int32(p.GetZL())
	// w.flag = 0
	return w
}
